#include "tokensmodel.h"
#include "variantmodel.h"

TokensModel::TokensModel(GElement* ele, QObject *parent)
	: mElement(ele), QAbstractItemModel(parent)
{

}

TokensModel::~TokensModel()
{

}

QModelIndex TokensModel::append(Token* newToken)
{
	int size = mElement->tokens().size();
	beginInsertRows(QModelIndex(), size, size);
	mElement->addToken(newToken);
	endInsertRows();
	return index(size,0);
}

void TokensModel::deleteAt(const QModelIndex & index)
{
	beginRemoveRows(QModelIndex(), index.row(), index.row());
	mElement->deleteToken(index.row());
	endRemoveRows();
}

void TokensModel::setTrace(const QModelIndex & index, const QStack<Trace> & trace)
{
	Token *token = static_cast<Token*>(index.internalPointer());
	token->setTraceStack(trace);
}

void TokensModel::moveUp(const QModelIndex & index)
{
	Q_ASSERT(index.isValid());
	int size = mElement->mTokens.size();
	int row = index.row();
	if (row<size && row>0) {
		mElement->mTokens.swap(row, row-1);
		QModelIndex topLeft = this->index(row-1,0);
		QModelIndex bottomRight = this->index(row,1);
		emit dataChanged(topLeft, bottomRight);
	}
}

QVariant TokensModel::headerData ( int section, Qt::Orientation orientation, int role ) const
{
	if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) {
		switch(section) {
		case 0:
			return QVariant(tr("Value"));
		case 1:
			return QVariant(tr("Type"));
		default:
			;
		}
	}
	return QAbstractItemModel::headerData(section, orientation, role);
}
int TokensModel::rowCount ( const QModelIndex & parent ) const
{
	return mElement->tokens().size();
}
int TokensModel::columnCount ( const QModelIndex & parent ) const
{
	return 2;
}

QVariant TokensModel::data ( const QModelIndex & index, int role ) const
{
	if (!index.isValid()) 
		return QVariant();

	if (role!=Qt::DisplayRole && role!=Qt::EditRole) 
		return QVariant();

	Token *token = static_cast<Token*>(index.internalPointer());
	if (index.column()==0) 
		return *token;
	else
		return QVariant::typeToName(token->type());
}

QModelIndex TokensModel::index ( int row, int column, const QModelIndex & parent ) const
{
	Q_ASSERT(!parent.isValid());
	if (row<mElement->tokens().size()) 
		return createIndex(row, column, mElement->tokens()[row]);
	else
		return QModelIndex();
}

QModelIndex TokensModel::parent ( const QModelIndex & index ) const
{
	//Q_ASSERT(!index.isValid());
	return QModelIndex();
}

Qt::ItemFlags TokensModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
		return Qt::ItemIsEnabled;
	Token *token = static_cast<Token*>(index.internalPointer());
	if ( (index.column()==0) && VariantModel::isCollection(token->type()))
		return QAbstractItemModel::flags(index);
	return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

//without explicit emit dataChanged(), view can work OK, 
//but cann't trigger other slots that connected by user.
//???Maybe the changed data are just in one row, or else wait to be test
//   such as another item's view can be affected. 

bool TokensModel::setData ( const QModelIndex & index, const QVariant & value, int role )
{
	if (!index.isValid() || role != Qt::EditRole)
		return false;

	Token *token = static_cast<Token*>(index.internalPointer());
	//QModelIndex weaken the pointer's type, and will make it unsafe
	//As here I use it.
	//token = const_cast<Token*>(token);
	if (index.column()==0) 
		token->setVariant(value);
	else {
		QVariant::Type type = static_cast<QVariant::Type>(value.toInt());
		if (token->canConvert(type)) 
			token->convert(type);
		else
			token->setVariant(QVariant(type));
	}
	//this is provided to compiler, just used to distinguish it from the parameter index.
	QModelIndex left = this->index(index.row(), 0); 
	QModelIndex right = this->index(index.row(), 1);
	emit dataChanged(left,right);
	return true;
}
